package main;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilePermission;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import p2p.Config;
import p2p.FileList;
import p2p.Kwalker;
import p2p.NeighborList;
import p2p.PeerPool;
import server.Message;
import server.RMIServer;

public class Peer {

	/**
	 * @param args
	 * @throws IOException 
	 * @throws RemoteException 
	 */
	public static void main(String[] args) throws IOException {
		int port = 0;
		String ip = "";

		try {
			InetAddress ia = InetAddress.getLocalHost();
			ip = ia.getHostAddress();
		} catch (UnknownHostException e) {
			System.out.println("ERROR: Unable to determine local IP");
		}


		String name;
		int maxNeighbours = 0;
		String superNode = "";
		int capacity = 2; //Capacity is either 0, 1 or 2, where 0 is the highest capacity
		String folderPath = "";

		if(args.length == 6) {
			port = Integer.parseInt(args[0]);
			name = args[1];

			maxNeighbours = Integer.parseInt(args[2]);
			if(!(maxNeighbours > 0 && maxNeighbours <= 10)) { //max neigbours
				System.out.println("ERROR: maxNeigbours must be greater than zero and smaller than or equal to ten");
				return;
			}

			superNode = args[3];
			folderPath = args[5];

			capacity = Integer.parseInt(args[4]);
			if(!(capacity >= 0 && capacity <= 2)) { //max neigbours
				System.out.println("ERROR: capacity must be greater than zero and smaller than or equal to two");
				return;
			}
			System.out.println(name+"("+maxNeighbours+")"+" is running on ip: "+ip+" and port: "+port+" with capacity: "+capacity+" and folder: "+folderPath.substring(folderPath.lastIndexOf("/")+1, folderPath.length()));
		} else {
			System.out.println("USAGE: Peer [port] [unique name] [maxNeighbours] [superNode] [capacity] [folder]"); 
			return;
		}

		//Local peer
		p2p.Peer thisPeer = new p2p.Peer(name, ip, port, maxNeighbours, capacity);

		//Peer pool
		PeerPool peerPool = new PeerPool(thisPeer);

		//Neighbor list
		NeighborList neighborList = new NeighborList(maxNeighbours, peerPool, thisPeer);

		//Move files to temporary folder 
		File[] fileBackup = new File(folderPath).listFiles(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				if(name.startsWith(".")) return false;
				return true;
			}
		});
		File temp = new File("temp/"+name);
		if(temp.exists()){
			for(File file :temp.listFiles()) file.delete();
		}else{
			temp.mkdirs();
		}
		for(int i = 0; i < fileBackup.length; i++){
			copyfile(fileBackup[i].getAbsolutePath(), temp.getAbsolutePath()+"/"+fileBackup[i].getName());
		}

		//File list
		FileList fileList  = new FileList(thisPeer, neighborList, temp);

		//K Walk plist
		Kwalker kWalker = new Kwalker(thisPeer, fileList, neighborList);

		//Server
		RMIServer s = null;
		try {
			s = new RMIServer(port, peerPool, neighborList, fileList, kWalker);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		/*
		 * initial hello
		 */
		String[] superIPPort = superNode.split(":");
		String superIP = superIPPort[0];
		int superPort = Integer.parseInt(superIPPort[1]);

		if(!(new p2p.Peer(superIP, superPort)).equals(thisPeer)) {
			Registry registry;
			Message rmiMessage;
			try {
				registry = LocateRegistry.getRegistry(superIP, superPort); //get the “registry” 
				rmiMessage = (Message)(registry.lookup(Config.ServerName)); //look up remote object
				rmiMessage.hello(thisPeer, Config.TTL); //call remote method
				System.out.println(thisPeer.getName()+" Connected to network");
			} catch(Exception e) {
				System.out.println(thisPeer.getName()+" Unable to connect to network");
			}
		}
		/*
		 * end initial hello
		 */
		//update
		@SuppressWarnings("unused")
		Thread threadUpdate = new Thread(new UpdateThread("threadUpdate", s, thisPeer, peerPool, neighborList, fileList/*, kWalker*/), "threadUpdate");

		//ui
		@SuppressWarnings("unused")
		Thread threadUI = new Thread(new UIThread("threadUI", s, thisPeer, peerPool, neighborList, fileList, kWalker), "threadUI");
	}

	private static void copyfile(String srFile, String dtFile){
		try{
			File f1 = new File(srFile);
			File f2 = new File(dtFile);
			InputStream in = new FileInputStream(f1);

			OutputStream out = new FileOutputStream(f2);

			byte[] buf = new byte[1024];
			int len;
			while ((len = in.read(buf)) > 0){
				out.write(buf, 0, len);
			}
			in.close();
			out.close();
		}
		catch(FileNotFoundException ex){
			System.out.println(ex.getMessage() + " in the specified directory.");
			System.exit(0);
		}
		catch(IOException e){
			System.out.println(e.getMessage());      
		}
	}

}